package com.re6g3y.game.Tile.Hexagonal.mapGenerate;

import com.badlogic.gdx.math.MathUtils;

import java.util.Random;

/**
 * http://www.geocomputation.org/1999/082/gc_082.htm
 */
public class GenerateChunk {
    private GenerateChunk(){}
    static final float scale=60f;
    public static float getTileHeight(float x,float y,int seed){
        float height=0;
        height+= getTerrain(x,y,seed,20f*scale)*0.6;
        int index=0;
        height+= getTerrain(x*rotatex[index]+y*rotatey[index],x*rotatey[index]-y*rotatex[index],seed,7f*scale)*0.25f;
        index=1;
        height+= getTerrain(x*rotatex[index]+y*rotatey[index],x*rotatey[index]-y*rotatex[index],seed,4f*scale)*0.1f;
        index=2;
        height+= getTerrain(x*rotatex[index]+y*rotatey[index],x*rotatey[index]-y*rotatex[index],seed,8f*scale)*0.05f;
        return  height;
    }

    static final int noise[];
    static final int noiseLen=0x3ffff;
    static float rotatex[];
    static float rotatey[];
    static {
        Random random=new Random(0x3f3f3f3f);
        noise=new int[noiseLen+1];
        for(int i=0;i<noiseLen+1;i++){
            noise[i]=random.nextInt(10000);
        }
        rotatex=new float[100];
        rotatey=new float[100];
        for(int i=0;i<100;i++){
            float rotate=random.nextFloat()*MathUtils.PI;
            rotatex[i]=MathUtils.sin(rotate);
            rotatey[i]=MathUtils.cos(rotate);
        }
    }

    /**
     * range[0,10000)
     * @param x
     * @param y
     * @param seed
     * @return
     */
    private static int getSeed(int x,int y,int seed){
//        return (x+y)%2==0?10000:0;
        return noise[(x+noise[(y+noise[seed&noiseLen])&noiseLen])&noiseLen];
    }

    private static float getTerrain(float x,float y,int seed,float scale){
        float v=x,u=y;
        v%=scale;v/=scale;
        if(v<0)v+=1;
        u%=scale;u/=scale;
        if(u<0)u+=1;
        int xx= MathUtils.floor(x/scale);
        int yy= MathUtils.floor(y/scale);
        float weight=0;
        for (int m = -1; m <= 2; m += 1) {
            for (int n = -1; n <= 2; n += 1) {
//                const rgba = getRGBAValue(
//                        data,
//                        width,
//                        height,
//                        intRow + m,
//                        intCol + n,
//                        );
                // 一定要正确区分 m,n和u,v对应的关系，否则会造成图像严重偏差（譬如出现噪点等）
                // F(row + m, col + n)S(m - v)S(n - u)
                float f1 = interpolationCalculate(m - v);
                float f2 = interpolationCalculate(n - u);
                weight += f1 * f2*getSeed(xx+m,yy+n,seed)/10000f;
            }
        }
//        System.out.println(x+" "+y+" "+weight);
        if(weight>1)weight=1;
        else if(weight<0)weight=0;
        return weight;
    }

    private static final float A = -0.5f;
    private static float interpolationCalculate(float x) {
        float absX = x > 0 ? x : -x;
        float x2 = x * x;
        float x3 = absX * x2;

        if (absX <= 1) {
            return 1 - (A + 3) * x2 + (A + 2) * x3;
        } else if (absX <= 2) {
            return -4 * A + 8 * A * absX - 5 * A * x2 + A * x3;
        }
        return 0;
    }
}

